package live.jialing.sip.base.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import live.jialing.authz.domain.SecurityGroup;
import live.jialing.authz.service.SecurityGroupService;
import live.jialing.core.data.LinkType;
import live.jialing.core.data.jpa.CustomJpaRepository;
import live.jialing.core.service.BaseDomainService;
import live.jialing.core.service.GeneralService;
import live.jialing.data.util.SpecificationUtil;
import live.jialing.sip.base.dict.ClassCategoryEnum;
import live.jialing.sip.base.dict.SchoolRoleEnum;
import live.jialing.sip.base.dict.SchoolTitleEnum;
import live.jialing.sip.base.domain.GradeGroup;
import live.jialing.sip.base.domain.School;
import live.jialing.sip.base.repository.GradeGroupRepository;
import live.jialing.sip.base.util.SchoolUtil;
import live.jialing.structure.domain.Employee;
import live.jialing.structure.domain.Position;
import live.jialing.structure.repository.PositionRepository;
import live.jialing.structure.service.EmployeeService;
import live.jialing.util.general.Collections3;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 年级
 */
@Service
public class GradeService extends BaseDomainService<GradeGroup, Long> implements GeneralService<GradeGroup, Long> {

    private static Logger logger = LoggerFactory.getLogger(GradeService.class);

    @Resource
    private GradeGroupRepository gradeGroupRepository;

    @Resource
    private SchoolService schoolService;

    @Resource
    private PositionRepository positionRepository;

    @Resource
    private EmployeeService employeeService;

    @Resource
    private SecurityGroupService securityGroupService;

    @Override
    public CustomJpaRepository getRepository() {
        return this.gradeGroupRepository;
    }

    public Specification<GradeGroup> buildSpecification(Class<GradeGroup> classz, Map<String, Object> searchParams, LinkType type) {

        return SpecificationUtil.buildSpecification(classz, searchParams, type);
    }

    /**
     * 新增年级组
     *
     * @param schoolId 学校ID
     * @param grade    入学年份
     * @param category 班级类型
     * @return
     */
    @Transactional
    public GradeGroup add(long schoolId, int grade, ClassCategoryEnum category) {

        School school = schoolService.findByPK(schoolId);
        if (school == null) {
            logger.warn("学校ID={}不正确，无此学校", schoolId);
            return null;
        }

        GradeGroup gradeGroup = new GradeGroup();
        gradeGroup.setGrade(grade);
        gradeGroup.setName(SchoolUtil.gradeName(category, grade) + "年级组");
        gradeGroup.setSchool(school);
        gradeGroup.setCategory(category);

        return gradeGroupRepository.save(gradeGroup);
    }

    /**
     * 设置组成员
     *
     * @param groupId    组id
     * @param employeeId 员工id
     * @param title      职务
     */
    @Transactional
    public void setupGroupMember(long groupId, long employeeId, String title) {

        GradeGroup gradeGroup = this.findByPK(groupId);
        if (gradeGroup == null) {
            return;
        }

        Employee employee = employeeService.findByPK(employeeId);
        if (employee == null) {
            return;
        }

        Position gradePosition = new Position();
        gradePosition.setCompanyId(gradeGroup.getSchool().getId());
        gradePosition.setGroupId(gradeGroup.getId());
        gradePosition.setEmployeeId(employee.getId());
        gradePosition.setTitle(title);
        positionRepository.save(gradePosition);
    }

    /**
     * 设置年级主任
     *
     * @param schoolId  学校ID
     * @param grade     入学年份
     * @param category  班级类型
     * @param teacherId 教职工ID
     * @see live.jialing.sip.base.dict.SchoolRoleEnum
     */
    @Transactional
    public void setupGradeMaster(long schoolId, int grade, ClassCategoryEnum category, long teacherId) {

        if (schoolId < 1 || grade < 2000 || teacherId < 1) {
            logger.warn("参数错误：schoolId={},grade={},teacherId={}", schoolId, grade, teacherId);
            return;
        }

        // 添加年级组
        GradeGroup group = findGradeGroupByGrade(schoolId, grade, category);
        if (group == null) {
            group = add(schoolId, grade, category);
        }

        // 设置为该年级组成员
        setupGroupMember(group.getId(), teacherId,SchoolTitleEnum.GRADE_MASTER.toString());

        // 设置为年级主任角色
        SecurityGroup securityGroup = securityGroupService.findSecurityGroupInOrgByCode(schoolId, SchoolRoleEnum.SCH_GRADE_MASTER.toString());
        securityGroupService.setupUsers(securityGroup.getId(), schoolId, Lists.newArrayList(teacherId));
    }

    /**
     * 获取某年级的年级组
     *
     * @param schoolId 学校id
     * @param grade    入学年份
     * @param category 班级分类
     * @return
     */
    public GradeGroup findGradeGroupByGrade(long schoolId, int grade, ClassCategoryEnum category) {

        if (grade < 2000) {
            return null;
        }

        Map<String, Object> searchParams = Maps.newTreeMap();
        searchParams.put("EQ_school.id", schoolId);
        searchParams.put("EQ_grade", grade);
        searchParams.put("EQ_category", category);
        Specification<GradeGroup> spec = SpecificationUtil.buildSpecification(GradeGroup.class, searchParams, LinkType.and);
        return gradeGroupRepository.findOne(spec);
    }

    /**
     * 根据学校、员工获取年级组
     *
     * @param schoolId   学校id
     * @param employeeId 员工id
     * @return
     */
    public List<GradeGroup> findGradeGroup(long schoolId, long employeeId) {

        if (schoolId < 1 && employeeId < 1) {
            return Lists.newArrayList();
        }

        List<Position> gradePositions = positionRepository.findByCompanyAndEmployee(schoolId, employeeId);
        if (Collections3.isEmpty(gradePositions)) {
            return Lists.newArrayList();
        }

        List<Long> ids = gradePositions.stream().filter(gp -> gp.getGroupId() != null)
                .map(gp -> gp.getGroupId()).distinct().collect(Collectors.toList());
        if (Collections3.isEmpty(ids)) {
            return Lists.newArrayList();
        }

        return this.findByPKs(ids);
    }


}
